package com.kgc.scd.service.impl;

import com.alibaba.fastjson.JSON;
import com.kgc.scd.bean.User;
import com.kgc.scd.bean.UserVO;
import com.kgc.scd.config.WechatPayConfig;
import com.kgc.scd.conntant.RedisPrefixConstant;
import com.kgc.scd.conntant.WechatPayConstant;
import com.kgc.scd.mapper.UserMapper;
import com.kgc.scd.service.WechatPayService;
import com.kgc.scd.util.HttpClient4Util;
import com.kgc.scd.util.LocalDateUtils;
import com.kgc.scd.util.RedisUtils;
import com.kgc.scd.util.WechatPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
/**
 * Created On : 2022/11/4.
 * <p>
 * Author : #jiangguoqiang
 * <p>
 * Description: 微信支付业务接口实现类
 */
@Service
@Slf4j
public class WechatPayServiceImpl implements WechatPayService {
    @Autowired
    private WechatPayConfig wechatPayConfig;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired(required = false)
    private UserMapper userMapper;
    /**
     * @return : java.lang.String
     * @author : Administrator
     * @date : 2022/11/4
     * @description : 生成请求微信支付的统一下单接口参数 ，xml格式字符串
     */
    @Override
    public String generateWxpayUnitfyOrderXmlParams(String productBody,int totalFee,String token) throws Exception {
        //微信支付接口，签名的参数要求
        //特别注意以下重要规则：
        //◆ 参数名ASCII码从小到大排序（字典序）；
        //◆ 如果参数的值为空不参与签名；
        //◆ 参数名区分大小写；

        //定义微信支付接口参数集合：TreeMap(自动根据集合中的key安装字典序排序，可以满足要求)
        Map<String,String> paramsMap = new TreeMap<>();

        //公众账号id
        paramsMap.put("appid", wechatPayConfig.getAppId());
        //商户号
        paramsMap.put("mch_id",wechatPayConfig.getMchId());
        //设备号，PC网页或公众号内支付可以传“WEB”
        paramsMap.put("device_info","WEB");
        //随机字符串
        paramsMap.put("nonce_str", WechatPayUtil.generateNonceStr());
        //商品的概要描述,可以使用当前系统的商品名
        paramsMap.put("body",productBody);
        //附加数据，直接返回，可以作为自定义参数使用
        paramsMap.put("attach",token);
        //商户订单号:商户系统内部订单号，要求32个字符内（最少6个字符），只能是数字、大小写字母_-|*且在同一个商户号下唯一
        paramsMap.put("out_trade_no",WechatPayUtil.generateTradeOrderNo());

        //标价金额，订单总金额，就是付款金额
        paramsMap.put("total_fee",String.valueOf(totalFee));
        //终端ip:支持IPV4和IPV6两种格式的IP地址。用户的客户端IP
        paramsMap.put("spbill_create_ip","192.168.1.163");
        //通知地址: 异步接收微信支付结果通知的回调地址，通知url必须为外网可访问的url，不能携带参数。
        paramsMap.put("notify_url",wechatPayConfig.getNotifyUri());

        //交易类型:NATIVE -Native
        paramsMap.put("trade_type", WechatPayConstant.WECHAT_PAY_TRADE_TYPE_NATIVE);

        //商品id：trade_type=NATIVE时，此参数必传。此参数为二维码中包含的商品ID，商户自行定义。
        paramsMap.put("product_id","互联网架构师");

        //签名,传送的sign参数不参与签名，将生成的签名与该sign值作校验,如果不一致，签名失败
        //切记：签名都是在确定好接口参数后，执行签名操作并将签名的结果加入参数集合
        paramsMap.put("sign",WechatPayUtil.generateSignature(paramsMap,wechatPayConfig.getMchKey()));

        //将微信支付统一下单接口转换为xml字符串
        return WechatPayUtil.generateMapToXml(paramsMap);
    }

    /**
     * @param unifyOrderXmlParams
     * @return : java.util.Map<java.lang.String,java.lang.String>
     * @author : Administrator
     * @date : 2022/11/10
     * @description : 请求微信支付统一接口，获取下单结果
     */
    @Override
    public Map<String, String> getWechatPayUnifyOrderResult(String unifyOrderXmlParams) throws Exception {

        //请求微信支付统一下单接口，请求微信下单统一接口，并获取下单结果，使用post请求
        String unifyOrderXmlResult = HttpClient4Util.getResponse4PostByString(wechatPayConfig.getOrderUri(),unifyOrderXmlParams,WechatPayConstant.WECHAT_PAY_ENCODING_UTF8);

        //将微信支付统一下单接口返回的xml格式字符串，转换为map集合返回

        return WechatPayUtil.generateXmlToMap(unifyOrderXmlResult);
    }

    /**
     * @param wxpayNotifyXmlResult
     * @return : java.lang.String
     * @author : Administrator
     * @date : 2022/11/11
     * @description : 解析异步回调结果，通知微信官方的回调结果
     */
    @Override
    public String getReturnWechatXllResult(String wxpayNotifyXmlResult) throws Exception {

        //将微信支付结果通知的xml格式字符串，转换为map集合，方便处理
        Map<String,String> wxpayNotifyMapResult =WechatPayUtil.generateXmlToMap(wxpayNotifyXmlResult);

        //解析返回回调结果
        if (WechatPayConstant.WECHAT_PAY_RESULT_SUCCESS.equals(wxpayNotifyMapResult.get("return_code"))
                && WechatPayConstant.WECHAT_PAY_RESULT_SUCCESS.equals(wxpayNotifyMapResult.get("result_code"))){
            //官方提醒：商户系统对于支付结果通知的内容一定要做签名验证，并讲演返回的订单金额是否与商户的订单金额一致，防止数据泄露，出现假付款

            if (WechatPayUtil.isSignatureValid(wxpayNotifyMapResult,wechatPayConfig.getMchKey())){
                //签名校验成功，说明回调结果可3信的，就可以进行业务处理，如果失败，说明会带哦来源不可信，不能进行业务处理
                //在redis中查询是否存在用户会员的key
                String token = wxpayNotifyMapResult.get("attach");
                UserVO userVo = JSON.toJavaObject(JSON.parseObject(redisUtils.get(token).toString()),UserVO.class);
                int num = Integer.parseInt(wxpayNotifyMapResult.get("total_fee"));
                if (redisUtils.hasKey(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId())){
                    log.info("------ 往redis中添加用户会员信息,信息存在,增加时长 ------");
                    //会员未过期，添加会员时长
                    Long time = null;
                    time = redisUtils.getExpire(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId());
                    LocalDateTime localDateTime1=LocalDateTime.parse(redisUtils.get(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId()).toString());
                    redisUtils.set(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId(),localDateTime1.plusDays(7*num));
                    redisUtils.expire(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId(),time + (604800*num));
                }else {
                    //用户不是会员，添加会员信息
                    log.info("------ 往redis中添加用户会员信息,信息不存在,创建用户vip信息 ------");
                    LocalDateTime localDateTime = LocalDateUtils.plus(new Date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(), 7, ChronoUnit.DAYS);
                    redisUtils.set(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId(),localDateTime,(604800*num));
                    log.info("------ 更新user表中用户的会员信息 ------");
                    User user = new User();
                    user.setId(userVo.getId());
                    user.setUserLevelId(true);
                    userMapper.updateById(user);
                    log.info("------ 更新redis中用户的token信息 ------");
                    userVo.setUserLevelId(true);
                    redisUtils.set(RedisPrefixConstant.LOGIN_TOKEN+token,userVo);
                }
                return WechatPayConstant.WECHAT_PAY_NOTIFY_RESP_SUCCESS;
            }
        }

        return WechatPayConstant.WECHAT_PAY_NOTIFY_RESP_FAIL;

    }

    /**
     * @param userVo
     * @return : java.lang.String
     * @author : Administrator
     * @date : 2022/11/17
     * @description : 查询当前用户的会员到期时间
     */
    @Override
    public String findUserMemberDate(UserVO userVo) {
        if (redisUtils.get(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId()) == null){
            return null;
        }else {
            return redisUtils.get(WechatPayConstant.REDIS_MEMBER_UNIFIED_PREFIX + userVo.getId()).toString();
        }
    }

    /**
     * @param user
     * @return : boolean
     * @author : Administrator
     * @date : 2022/11/17
     * @description : 更新会员时间
     */
    @Override
    public boolean modUser(User user) {
        return userMapper.updateById(user) > 0;
    }
}
